-- 2022-8-3

---[[
    -- 捕获机制允许根据一个模式从目标字符串中抽出与该模式匹配的内容来用于后续用途，可以通过把模式中需要捕获的部分放到一对圆括号内来指定捕获

    -- 对于具有捕获的模式，函数string.match会将所有捕获到的值作为单独的结果返回，换句话说，该函数会将字符串切分成多个被捕获的部分
    do
        local pair = "name = Anna"
        local key,value = string.match(pair,"(%a+)%s*=%s*(%a+)")
        print(key,value)
    end
    -- %a+表示一个非空字母序列，模式%s*表示可空的空白序列
    -- 因此，上例中的这个模式表示一个字母序列，紧跟着空白序列，一个等号，空白序列以及另一个字母序列
    -- 模式中的两个字母序列被分别放在圆括号中，因此在匹配时就能捕获到它们
    do
        local date = "Today is 8/3/2022"
        local d,m,y = string.match(date,"(%d+)/(%d+)/(%d+)")
        print(d,m,y)
    end
    -- 假设在一个字符串中寻找一个由单引号或双引号括起来的子串
    -- 那么可能会尝试使用'["'].-["']'，但是在处理的时候可能会出现 "和' 匹配的情况
    -- 要解决这个问题，可以捕获第一个引号用它来指明第二个引号
    do
        local s = [[then he said : "it's all right"!]]
        local p,q = string.match(s,"([\"'])(.-)%1")
        print(p,q)
    end
    -- 第一个捕获的是引号本身，第二个捕获的是引号中的内容

    -- 下例是一个类似的示例，用于匹配Lua语言中的长字符串的模式
    -- %[(=*)%[(.-)%]%1%]
    do
        local p = "%[(=*)%[(.-)%]%1%]"
        local s = "a = [=[[[ something ]] ]==] ]=] ; print(a)"
        print(string.match(s,p))
    end
    -- 第一个捕获等号，第二个捕获内容

    -- 被捕获对象的第三个用途是在函数gsub的替代字符串中
    -- 像模式一样，替代字符串同样可以包括像"%n"一样的字符分类，当发生替换时会被替换为相应的捕获
    -- 特别的，"%0"意味着整个匹配，并且替换字符串的百分号必须被转义为"%%"
    -- 下面这个示例会重复字符串中的每个字符，并且在每个被重复的字母之间插入一个减号
    do
        print(string.gsub("hello lua","%a","%0-%0"))
        print(string.gsub("hello lua","(.)(.)","%2%1"))
    end

    -- 以下是一个更有用的示例，让我们编写一个原始的格式转换器，该格式转换器能读取LATEX风格的命令，并将它们转换为XML风格
    -- \command{soem text} --> <command>soem text</command>
    -- 如果不考虑嵌套的命令，我们可以这样(后面会学习到嵌套的处理)
    do
        local s = [[the \quote{task} is to \em{change} that.]]
        s = string.gsub(s,"\\(%a+){(.-)}","<%1>%2</%1>")
        print(s)
    end

    -- 另一个更有用的是剔除字符串两端空格
    do
        function Trim(s)
            s = string.gsub(s,"^%s*(.-)%s*$","%1")
            return s
        end
    end

    -- 注意模式中修饰符的合理运用，两个定位标记(^和$)保证了我们可以获取到整个字符串，(.-)匹配尽可能少的字符
--]]